<?php
/**
 * HTML出力補助モジュール
 * HTML
 * 
 * 主にViewモジュールの補佐を行う
 * 
 * @since 2012/02/03
 */
class HTML {
	public function __construct () {
		// Moduleに設置する
		$obj = Y('Module')->add($this, __CLASS__);
		
		$obj->addAllMethod ();
	}
	
	/**
	 * これ自体のcallは意味なし。
	 * 
	 * @since 2012/02/03
	 */
	public function call () {}

	/**
	 * 新しいフォームを定義する
	 * フォーム
	 * 
	 * @since 2012/02/03
	 */
	public function Form ($name, $action, $method, $items=array()) {
		if (($form = Y('Form', false)) == false) $form = Y()->add('Form', null);
		$form->add ($name, new HTMLForm ($name, $action, $method, $items));
	}
}

/**
 * フォームを定義、出力するクラス
 * 
 * @since 2012/02/11
 */
class HTMLForm {
	private $_name;
	private $_action;
	private $_method;
	private $_defItems = array (
		'Submit'=>array('type'=>'submit', 'value'=>'Submit'),
		'Reset'=>array('type'=>'reset', 'value'=>'Reset'),
		'Close'=>array('type'=>'close'),
	);
	
	/**
	 * コンストラクタにはフォームの名称とaction属性を指定する。
	 * また、同時に配列でフォームアイテムを指定することもできる。
	 * (後から追加しても有効)
	 * 
	 * @since 2012/02/11
	 */
	public function __construct ($name, $action, $method = 'get', $items = array()) {
		$this->_name = $name;
		$this->_action = $action;
		$this->_method = $method;
		$this->_defItems = array_merge ($this->_defItems, $items);
	}
	
	/**
	 * callするとフォームを開始する
	 * 
	 * @since 2012/02/03
	 */
	public function call () {
		$form = Y::sel();
		
		// defItemsを追加する。同名のものが既に追加されている場合何もしない。
		foreach ($this->_defItems as $name=>$item) {
			if ($form->child($name)->isEmpty()) {
				$form->add ($name, $item);
			}
		}

		$i = 0;
		while ($item = $form->child($i++, false)) {
			$item->set(Y::func($this, 'putForm'));
		}

		return '<form name="'.$this->_name.'" id="'.$this->_name.'" method="'.$this->_method.'" action="'.$this->_action.'">';
	}

	/**
	 * フォームコントロールを配置する
	 * 
	 * @since 2012/02/03
	 */
	public function putForm () {
		$form = Y::sel();
		$tag = '';
		$tag .= $form->child('before')->sput(false);
		// タグの生成は各サブメソッドに渡す。
		$type = '_putForm'.$form->child('type')->call();
		if (method_exists ($this, $type)) {
			$tag = $this->$type($form);
		} else {
			$tag = $this->_putFormDefaultType($form);
		}
		$tag .= $form->child('after')->sput(false);
		return $tag;
	}

	/**
	 * その他一般のフォームアイテム(input)を出力する
	 * 基本的にtype="text"の前提。
	 * 
	 * @since 2012/02/12
	 */
	private function _putFormDefaultType ($form) {
		$name = $form->getName();
		$tag  = '<input name="'.$name.'" id="'.$name.'"';
		$tag .= $form->child('type')->sput('hidden', ' type="%s"');
		$tag .= $form->child('value')->escape('html')->sput(false, ' value="%s"');
		$tag .= $form->child('etc')->sput(false);
		$tag .= ' />';
		return $tag;
	}
	
	/**
	 * Textareaを出力する
	 * 
	 * @since 2012/02/12
	 */
	private function _putFormTextarea ($form) {
		$name = $form->getName();
		$tag  = '<textarea name="'.$name.'" id="'.$name.'"';
		$tag .= $form->child('etc')->sput(false);
		$tag .= '>'."\n";
		$tag .= $form->child('value')->escape('html')->sput(false);
		$tag .= "\n".'</textarea>';
		return $tag;
	}
	
	/**
	 * Submitボタンを出力する
	 * 
	 * @since 2012/02/12
	 */
	private function _putFormSubmit ($form) {
		$name = $form->getName();
		$tag  = '<input name="'.$name.'" id="'.$name.'" type="submit"';
		$tag .= $form->child('value')->escape('html')->sput(false, ' value="%s"');
		$tag .= $form->child('etc')->sput(false);
		$tag .= ' />';
		return $tag;
	}

	/**
	 * フォームを閉じる
	 * 
	 * @since 2012/02/12
	 */
	private function _putFormClose ($form) {
		return '</form>';
	}
}

new HTML();